001    package net.sf.xdc.util;
002    
003    /*
004     *  Copyright 2005-2006 Jens Voß.
005     *
006     *  Licensed under the GNU Lesser General Public License (the "License");
007     *  you may not use this file except in compliance with the License.
008     *  You may obtain a copy of the License at
009     *
010     *       http://opensource.org/licenses/lgpl-license.php
011     *
012     *  Unless required by applicable law or agreed to in writing, software
013     *  distributed under the License is distributed on an "AS IS" BASIS,
014     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     *  See the License for the specific language governing permissions and
016     *  limitations under the License.
017     */
018    
019    import java.io.File;
020    import java.io.IOException;
021    import java.io.InputStream;
022    import java.io.OutputStream;
023    import java.io.Reader;
024    import java.io.Writer;
025    import java.io.FileReader;
026    import java.io.FileWriter;
027    import java.io.FileOutputStream;
028    import java.io.OutputStreamWriter;
029    import java.io.FileInputStream;
030    import java.io.InputStreamReader;
031    import java.io.FileNotFoundException;
032    import java.util.Collection;
033    import java.util.Arrays;
034    import java.nio.charset.Charset;
035    
036    /**
037     * This utility class contains a number of useful static methods related to
038     * Stream manipulation.
039     *
040     * @author Jens Voß
041     * @since 0.5
042     * @version 0.5
043     */
044    public class IOUtils {
045    
046      private static final int DEFAULT_BUFFER_SIZE = 4096;
047      private static final Collection DEFAULT_EXCLUDES = Arrays.asList(new String[] {
048              "CVS",
049              ".cvsignore",
050              "SCCS",
051              "vssver.scc",
052              ".svn",
053              ".DS_Store"
054      });
055    
056    
057      /**
058       * Reads byte data in chunks of a specified size from one stream and writes
059       * it into another stream.
060       *
061       * @param input  The InputStream from which to read the data
062       * @param output The OutputStream to which to write the data
063       * @throws IOException
064       */
065      public static void copy(final InputStream input,
066                              final OutputStream output)
067              throws IOException {
068        if (input == null) {
069          return;
070        }
071        final byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
072        int n;
073        while ((n = input.read(buffer)) != -1) {
074          output.write(buffer, 0, n);
075        }
076      }
077    
078      /**
079       * Reads character data in chunks of a specified size from a Reader and
080       * writes it into a Writer.
081       *
082       * @param input  The Reader from which to read the data
083       * @param output The Writer to which to write the data
084       * @throws IOException
085       */
086      public static void copy(final Reader input,
087                              final Writer output) throws IOException {
088        if (input == null) {
089          return;
090        }
091        final char[] buffer = new char[DEFAULT_BUFFER_SIZE];
092        int n;
093        while ((n = input.read(buffer)) != -1) {
094          output.write(buffer, 0, n);
095        }
096      }
097    
098      private static void copy(final File inFile, final File outFile)
099              throws IOException {
100        InputStream in = null;
101        OutputStream out = null;
102        try {
103          in = new FileInputStream(inFile);
104          out = new FileOutputStream(outFile);
105          copy(in, out);
106        }
107        finally {
108          if (in != null) {
109            in.close();
110          }
111          if (out != null) {
112            out.close();
113          }
114        }
115      }
116    
117      /**
118       * This method is used to completely delete all contents of a directory
119       * including all files and (recursively) subdirectories, but not the
120       * (specified) directory itself.
121       *
122       * @param directory The directory whose contents are to be deleted
123       * @return <b>true</b> if the directory contains no more files after this
124       *         operation; <b>false</b> otherwise (i.e. if some file could not be
125       *         deleted for some reason)
126       */
127      public static boolean makeEmpty(File directory) {
128        File[] files = directory.listFiles();
129        if (files == null) {
130          return true;
131        }
132        boolean retVal = true;
133        for (int i = 0; i < files.length; i++) {
134          File file = files[i];
135          if (file.isDirectory()) {
136            retVal &= makeEmpty(file);
137          }
138          retVal &= file.delete();
139        }
140        return retVal;
141      }
142    
143      /**
144       * This method is used to determine whether a path constituent should be
145       * excluded from processing because it is most likely a directory or file
146       * containing version control information.<br/>
147       * Excluded filename patterns are:
148       * <ul>
149       *   <li>*~
150       *   <li>#*#
151       *   <li>.#*
152       *   <li>%*%
153       *   <li>._*
154       *   <li>CVS
155       *   <li>.cvsignore
156       *   <li>SCCS
157       *   <li>vssver.scc
158       *   <li>.svn
159       *   <li>.DS_Store
160       * </ul>
161       *
162       * @param filename The name of the path constituent (directory or file) for
163       *        which a check is performed
164       * @return <b>true</b> if the filename matches one of the above patterns;
165       *         <b>false</b> otherwise
166       */
167      public static boolean isDefaultExclude(String filename) {
168        return filename.endsWith("~")
169                  || (filename.startsWith("#") && filename.endsWith("#"))
170                  || filename.startsWith(".#")
171                  || (filename.startsWith("%") && filename.endsWith("%"))
172                  || filename.startsWith("._")
173                  || DEFAULT_EXCLUDES.contains(filename);
174      }
175    
176      /**
177       * This method is used to recursively copy the contents of one
178       * complete directory tree from one location in the file system
179       * to another.
180       *
181       * @param srcDir The source directory whose contents are to be
182       *        copied
183       * @param targetDir The target directory (to which the contents
184       *        of the source directory are copied)
185       * @throws IOException
186       */
187      public static void copyTree(File srcDir, File targetDir) throws IOException {
188        File[] files = srcDir.listFiles();
189        for (int i = 0; i < files.length; i++) {
190          File file = files[i];
191          File outFile = new File(targetDir, file.getName());
192          if (file.isFile()) {
193            copy(file, outFile);
194          }
195          else if (file.isDirectory()) {
196            outFile.mkdir();
197            copyTree(file, outFile);
198          }
199        }
200      }
201    
202      /**
203       * This method constructs a <code>Reader</code> object of a <code>File</code>
204       * for a given <code>Charset</code>.
205       *
206       * @param file The file for which the <code>Reader</code> is to be
207       *        constructed
208       * @param charset The <code>Charset</code> of the <code>Reader</code>
209       *        to be constructed
210       * @return A <code>Reader</code> object for the specified <code>File</code>
211       *         with the specified <code>Charset</code>
212       * @throws FileNotFoundException
213       */
214      public static Reader getReader(File file, Charset charset) throws FileNotFoundException {
215        if (charset != null) {
216          FileInputStream stream = new FileInputStream(file);
217          return new InputStreamReader(stream, charset);
218        }
219        else {
220          return new FileReader(file);
221        }
222      }
223    
224      /**
225       * This method constructs a <code>Reader</code> object of a <code>File</code>
226       * for a given <code>Charset</code>.
227       *
228       * @param filename The name of the file for which the <code>Reader</code>
229       *        is to be constructed
230       * @param charset The <code>Charset</code> of the <code>Reader</code>
231       *        to be constructed
232       * @return A <code>Reader</code> object for the specified <code>File</code>
233       *         with the specified <code>Charset</code>
234       * @throws FileNotFoundException
235       */
236      public static Reader getReader(String filename, Charset charset) throws FileNotFoundException {
237        if (charset != null) {
238          FileInputStream stream = new FileInputStream(filename);
239          return new InputStreamReader(stream, charset);
240        }
241        else {
242          return new FileReader(filename);
243        }
244      }
245    
246      /**
247       * This method constructs a <code>Writer</code> object of a <code>File</code>
248       * for a given <code>Charset</code>.
249       *
250       * @param file The file for which the <code>Writer</code> is to be
251       *        constructed
252       * @param charset The <code>Charset</code> of the <code>Writer</code>
253       *        to be constructed
254       * @return A <code>Writer</code> object for the specified <code>File</code>
255       *         with the specified <code>Charset</code>
256       * @throws FileNotFoundException
257       */
258      public static Writer getWriter(File file, Charset charset) throws IOException {
259        if (charset != null) {
260          FileOutputStream stream = new FileOutputStream(file);
261          return new OutputStreamWriter(stream, charset);
262        }
263        else {
264          return new FileWriter(file);
265        }
266      }
267    
268      /**
269       * This method constructs a <code>Writer</code> object of a <code>File</code>
270       * for a given <code>Charset</code>.
271       *
272       * @param filename The name of the file for which the <code>Writer</code>
273       *        is to be constructed
274       * @param charset The <code>Charset</code> of the <code>Writer</code>
275       *        to be constructed
276       * @return A <code>Writer</code> object for the specified <code>File</code>
277       *         with the specified <code>Charset</code>
278       * @throws FileNotFoundException
279       */
280      public static Writer getWriter(String filename, Charset charset) throws IOException {
281        if (charset != null) {
282          FileOutputStream stream = new FileOutputStream(filename);
283          return new OutputStreamWriter(stream, charset);
284        }
285        else {
286          return new FileWriter(filename);
287        }
288      }
289    
290      private IOUtils() {
291      }
292    
293    }